package cn.code4java.springbok.service.impl;

import cn.code4java.springbok.CodeGenerator;
import cn.code4java.springbok.config.GenTemplateConfig;
import cn.code4java.springbok.config.GenTemplateParam;
import cn.code4java.springbok.constant.SpringbokConstant;
import cn.code4java.springbok.dto.TableDTO;
import cn.code4java.springbok.entity.Table;
import cn.code4java.springbok.entity.TableColumn;
import cn.code4java.springbok.enums.DBJavaTypeMapEnum;
import cn.code4java.springbok.enums.ModeEnum;
import cn.code4java.springbok.exception.BusinessException;
import cn.code4java.springbok.exception.ExceptionEnum;
import cn.code4java.springbok.mapper.TableColumnMapper;
import cn.code4java.springbok.mapper.TableMapper;
import cn.code4java.springbok.service.BaseServiceImpl;
import cn.code4java.springbok.service.TableService;
import cn.code4java.springbok.utils.StringUtils;
import cn.code4java.springbok.vo.TableVO;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @ClassName TableServiceImpl
 * @Description: 服务实现类
 * @Author xiehuangbao
 * @Date 2024/07/09
 * @Version 2.0.0
 **/
@Service
@AllArgsConstructor
public class TableServiceImpl extends BaseServiceImpl<TableMapper, Table> implements TableService {

    private TableColumnMapper tableColumnMapper;

    /**
     * 分页查询
     *
     * @param params
     * @return
     */
    @Override
    public Page<Table> pageTable(TableDTO params) {
        return this.page(getPage());
    }

    /**
     * 新增表
     *
     * @param tableDTO
     * @return
     */
    @Override
    @Transactional
    public boolean addTable(TableDTO tableDTO) {
        if (CollectionUtil.isEmpty(tableDTO.getTableColumns())) {
            throw new BusinessException(ExceptionEnum.BUSINESS_PARAM_NOT_NULL_ERROR, "表字段不能为空");
        }
        tableDTO.setClassName(StringUtils.underlineToPascalCase(tableDTO.getTableName()));
        this.save(tableDTO);
        tableDTO.getTableColumns().stream().forEach(tableColumn -> {
            tableColumn.setTableId(tableDTO.getTableId());
            tableColumn.setFieldName(StringUtils.underlineToCamelCase(tableColumn.getColumnName()));
            DBJavaTypeMapEnum dbJavaTypeMapEnum = DBJavaTypeMapEnum.getDBJavaTypeMapEnum(tableColumn.getColumnType());
            tableColumn.setFieldType(dbJavaTypeMapEnum.getJavaType());
            tableColumn.setColumnComment(StringUtils.isBlank(tableColumn.getColumnComment()) ? tableColumn.getColumnName() : tableColumn.getColumnComment());
            tableColumnMapper.insert(tableColumn);
        });
        return true;
    }

    /**
     * 修改表
     *
     * @param tableDTO
     * @return
     */
    @Override
    @Transactional
    public boolean updateTable(TableDTO tableDTO) {
        if (CollectionUtil.isEmpty(tableDTO.getTableColumns())) {
            throw new BusinessException(ExceptionEnum.BUSINESS_PARAM_NOT_NULL_ERROR, "表字段不能为空");
        }
        tableDTO.setClassName(StringUtils.underlineToPascalCase(tableDTO.getTableName()));
        this.updateById(tableDTO);
        tableColumnMapper.delete(Wrappers.<TableColumn>lambdaQuery().eq(TableColumn::getTableId, tableDTO.getTableId()));
        tableDTO.getTableColumns().stream().forEach(tableColumn -> {
            tableColumn.setTableId(tableDTO.getTableId());
            tableColumn.setFieldName(StringUtils.underlineToCamelCase(tableColumn.getColumnName()));
            DBJavaTypeMapEnum dbJavaTypeMapEnum = DBJavaTypeMapEnum.getDBJavaTypeMapEnum(tableColumn.getColumnType());
            tableColumn.setFieldType(dbJavaTypeMapEnum.getJavaType());
            tableColumn.setColumnComment(StringUtils.isBlank(tableColumn.getColumnComment()) ? tableColumn.getColumnName() : tableColumn.getColumnComment());
            tableColumnMapper.insert(tableColumn);
        });
        return true;
    }

    /**
     * 删除表
     *
     * @param id
     * @return
     */
    @Override
    @Transactional
    public boolean deleteTable(Integer id) {
        tableColumnMapper.delete(Wrappers.<TableColumn>lambdaQuery().eq(TableColumn::getTableId, id));
        return this.removeById(id);
    }

    /**
     * 根据id查询
     *
     * @param id
     * @return
     */
    @Override
    public TableVO selectTableById(Integer id) {
        List<TableColumn> tableColumns = tableColumnMapper.selectList(Wrappers.<TableColumn>lambdaQuery().eq(TableColumn::getTableId, id));
        Table table = this.getById(id);
        TableVO tableVO = new TableVO();
        BeanUtils.copyProperties(table, tableVO);
        tableVO.setTableColumns(tableColumns);
        return tableVO;
    }

    /**
     * 生成代码zip压缩包
     *
     * @param tableId
     * @param response
     * @throws Exception
     */
    @Override
    public void generateCode(Integer tableId, HttpServletResponse response) throws Exception {
        // 获取待打包的目录路径
        Table table = this.getById(tableId);
        List<TableColumn> tableColumns = tableColumnMapper.selectList(Wrappers.<TableColumn>lambdaQuery().eq(TableColumn::getTableId, tableId));
        GenTemplateConfig config = new GenTemplateConfig.Builder()
                .outPath(table.getOutPath()) // 生成的路径
                .mode(ModeEnum.CAMEL_CASE.name()) // 生成的字段命名方式
                .author(table.getAuthor())
                .version(SpringbokConstant.VERSION)
                .packageName(table.getPackageName())
                .build();
        CodeGenerator generator = new CodeGenerator(config);
        generator.setTemplateParam(table, tableColumns);
        generator.generate();

        // 设置响应内容类型为ZIP文件
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=files.zip");

        // 创建ZIP输出流
        ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());

        // 递归打包目录
        try {
            zipDirectory(new File(config.getOutPath()), "", zipOut);
            zipOut.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void zipDirectory(File directory, String parentPath, ZipOutputStream zipOut) throws IOException {
        byte[] buffer = new byte[1024];
        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                zipDirectory(file, parentPath + file.getName() + File.separator, zipOut);
            } else {
                FileInputStream fileIn = new FileInputStream(file);
                ZipEntry zipEntry = new ZipEntry(parentPath + file.getName());
                zipOut.putNextEntry(zipEntry);
                int len;
                while ((len = fileIn.read(buffer)) > 0) {
                    zipOut.write(buffer, 0, len);
                }
                fileIn.close();
            }
        }
    }
}
